# coding:utf-8
# 卡牌管理

import traceback, uuid, copy, time
from sqlalchemy import and_, or_
import glog, gdb
from card import *
from db_tables import *


# { role_id : {item_id1 : item1, ..}, .. }
data = {}

def init ():
    pass


# 升级技能等级
def card_level_up(role_id, card_id, to_drops):
    #* 检测技能类型,最大值判断
    #* 消耗物品

    card = get(role_id, card_id)
    if not card:
        glog.error("card_mgr>card_level_up, no this id, owner:%s, id:%s" % (role_id,card_id))
        return False, '参数错误'

    for cid in to_drops:
        c = get(role_id, cid)
        if not c:
            glog.error("card_mgr>card_level_up, to_drops no this id, owner:%s, id:%s" % (role_id,cid))
            return False, '参数错误'

    if card_id in to_drops:
        glog.error("card_mgr>card_level_up, target card in to_drops, owner:%s, id:%s" % (role_id,card_id))
        return False, '不能吞噬目标卡牌'

    #* 这里不可rollback了
    for cid in to_drops:
        remove_by_id(role_id, cid)

    # 复制一个对象
    data = copy.deepcopy(card)
    data.level += 1

    if not update(role_id, card_id, data):
        return False, '数据写入错误'

    return True, ''


def card_quality_up(role_id, card_id):
    t1 = time.time()
    #* 消耗对应道具

    card = get(role_id, card_id)
    if not card:
        glog.error("card_mgr>card_quality_up, no this id, owner:%s, id:%s" % (role_id,card_id))
        return False, '参数错误'

    # 复制一个对象
    data = copy.deepcopy(card)
    data.quality += 1

    if not update(role_id, card_id, data):
        return False, '数据写入错误'

    t2 = time.time()
    glog.debug('card_quality_up db time:'+str(t2-t1));
    return True, ''


# --------------------------------------------------
# 取得道具
def get (owner, card_id):
    if owner not in data:
        _load_by_owner(owner)

    items = data[owner]
    if card_id not in items:
        glog.error("card_mgr>get, no this id, owner:%s, id:%s" % (owner,card_id))
        return None
    return items[card_id]


# 获得全部道具, 返回列表
def get_by_owner (owner):
    if owner not in data:
        _load_by_owner(owner)

    items = data[owner]
    return items

    
# 从数据库中加载数据 {item_id1 : item1, ..}
def _load_by_owner (owner):
    dbitems = db_get_by_owner(owner)
    
    items = {}
    for dbitem in dbitems:
        item = Card()
        _dbcard_to_card(dbitem, item)
        items[item.id] = item

    # 写入内存
    data[owner] = items


# 增加道具数量
def add (owner, card_type, amount):
    if (db_create(owner, card_type, amount)):
        # 添加成功,重新从数据库读取
        _load_by_owner(owner)
        return True
    return False


# 减少道具数量
def remove (owner, card_type, amount):
    if (db_delete(owner, card_type, amount)):
        # 重新从数据库读取
        _load_by_owner(owner)
        return True
    return False


def remove_by_id (owner, card_id):
    if (db_delete_by_id(card_id)):
        # 重新从数据库读取
        _load_by_owner(owner)
        return True
    return False


# 更改道具属性
def update (owner, card_id, data):
    # 数据库
    card = get(owner, card_id)
    if not card:
        glog.error("card_mgr>update, no this id, owner:%s, id:%s" % (owner,card_id))
        return False

    if not db_update(card_id, data):
        glog.error("card_mgr>update, do update FAILED, owner:%s, id:%s" % (owner,card_id))
        return False

    # 内存
    _copy_attrs(data, card)
    return True


# 转化dbitem到Item
def _dbcard_to_card (dbcard, card):
    card.id = dbcard.id
    _copy_attrs(dbcard, card)


# 复制card属性(不含id)
def _copy_attrs (src, dst):
    dst.owner = src.owner
    dst.type = src.type

    dst.exp = src.exp
    dst.level = src.level
    dst.quality = src.quality

    dst.energy = src.energy
    dst.add_atk = src.add_atk
    dst.add_def = src.add_def
    dst.add_hp = src.add_hp
    dst.add_spd = src.add_spd


# ------------------------------------------------------
def db_create (owner, card_type, amount):
    ses = gdb.get_session()
    try:
        for i in xrange(amount):
            id = uuid.uuid1().hex   # 道具ID
            ses.add(DBCard(id, owner, card_type, 0,0,0, 0,0,0,0,0)) # 创建DB对象
        ses.commit()
        return True
    except Exception, e:
        ses.rollback()
        glog.error("card_mgr>db_create FAILED (owner:%s, card_type:%d, amount:%d)" % (owner, card_type, amount))
        return False


def db_delete (owner, card_type, amount):
    ses = gdb.get_session()
    try:
        # 筛选出需要删除的db对象
        to_dels = []

        #* PS:因为传递参数的时候不支持'type', 所以手工做过滤
        _items = ses.query(DBCard).filter_by(owner=owner).all()
        items = [i for i in _items if i.type==card_type]
        
        for item in items:
            to_dels.append(item)
            if len(to_dels) >= amount: break

        # 没有删除足够的数量,记录日志
        if len(to_dels) < amount:
            glog.warning("card_mgr>db_delete WARNING:not enough (owner:%s, card_type:%d, amount:%d, real_delete:%d)" % (owner, card_type, amount, len(to_dels)))

        # 删除
        for item in to_dels: ses.delete(item)
        ses.commit()
        return True
    except Exception, e:
        ses.rollback()
        glog.error("card_mgr>db_delete FAILED (owner:%s, card_type:%d, amount:%d)" % (owner, card_type, amount))
        raise e
        return False


def db_delete_by_id (id):
    ses = gdb.get_session()

    dbcard = ses.query(DBCard).filter_by(id=id).first()
    if dbcard is None:
        glog.error("card_mgr>db_delete_by_id FAILED (no this id:%s)" % id)
        return False

    ses.delete(dbcard)
    ses.commit()
    return True
    

def db_get (id):
    ses = gdb.get_session()
    return ses.query(DBCard).filter_by(id=id).first()


def db_get_by_owner (owner):
    ses = gdb.get_session()
    return ses.query(DBCard).filter_by(owner=owner).all()


def db_update (id, card):
    ses = gdb.get_session()

    dbcard = ses.query(DBCard).filter_by(id=id).first()
    if dbcard is None:
        glog.error("card_mgr>db_update FAILED (no this id:%s)" % id)
        return False

    try:
        _copy_attrs(card, dbcard)
        ses.commit()
    except Exception, e:
        ses.rollback()
        glog.error("card_mgr>db_update FAILED (id:%s)" % id)
        raise e
        return False
    return True
